package com.maple.common.widget

import android.content.Context
import android.graphics.Canvas
import android.text.StaticLayout
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatTextView
import com.maple.common.R
import com.maple.common.utils.ConstCommon
import com.maple.common.utils.LanguageUtil
import androidx.core.content.withStyledAttributes

/**
 * Tip:
 * Create by SeVen on 2024/4/22 20:03
 */
class AlignBothTextView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : AppCompatTextView(context, attrs, defStyleAttr) {
    // 是否打开左右对齐功能
    private var alignBothSide = false

    init {
        initAttr(context, attrs)
    }

    private fun initAttr(context: Context, attrs: AttributeSet?) {
        attrs?.let {
            context.withStyledAttributes(attrs, R.styleable.AlignBothTextView) {
                apply {
                    for (i in 0 until indexCount) {
                        when (val attr = getIndex(i)) {
                            R.styleable.AlignBothTextView_alignBothSide -> {
                                alignBothSide = getBoolean(attr, false)
                            }
                        }
                    }
                }
            }
        }
    }

    override fun onDraw(canvas: Canvas) {
        if (text !is String) {
            super.onDraw(canvas)
        } else {
            paint.color = currentTextColor
            for (i in 0 until layout.lineCount) { // 遍历textView中每行字符
                // 记录文本框内部padding值 上左右
                val lineBaseline = layout.getLineBaseline(i)
                val lineStart = layout.getLineStart(i)
                val lineEnd = layout.getLineEnd(i)
                if (alignBothSide) { // 如果要两边对齐
                    // 如果i行是最后一行,无需计算直接输出
                    if (i == layout.lineCount - 1) {
                        canvas.drawText(
                            text.substring(lineStart),
                            paddingLeft.toFloat(),
                            lineBaseline.toFloat(),
                            paint
                        )
                        break
                    } else {// 如果i行不是最后一行
                        val line = text.substring(lineStart, lineEnd)
                        val width =
                            StaticLayout.getDesiredWidth(text, lineStart, lineEnd, paint)
                        // 2. 根据语种进行不同的绘制方法：类中文、从右往左念类阿拉伯文、类英文
                        if (languageChineseType()) {
                            drawChineseScaledText(
                                canvas,
                                line,
                                lineBaseline.toFloat(),
                                width
                            )
                        } else if (languageArabicType()) {
                            drawArabicScaledText(
                                canvas,
                                line,
                                lineBaseline.toFloat(),
                                width
                            )
                        } else {
                            drawScaledText(canvas, line, lineBaseline.toFloat(), width)
                        }
                    }
                } else { // 如果不要两边对齐，直接绘制这一行的文本
                    canvas.drawText(
                        text.substring(lineStart, lineEnd),
                        paddingLeft.toFloat(),
                        lineBaseline.toFloat(),
                        paint
                    )
                }
            }
        }
    }


    /**
     * 在canvas上绘制一行文本
     * @param line 一行的字符
     * @param baseLineY 基线垂直方向offset，每个字符绘制时y坐标点
     * @param lineWidth 当前行的总长度
     */
    private fun drawScaledText(
        canvas: Canvas?,
        line: String,
        baseLineY: Float,
        lineWidth: Float
    ) {
        if (line.isEmpty()) {
            return
        }
        val endIndex = line.length - 1
        if (line[endIndex].code == ConstCommon.ASCII_ENTER || endIndex == ConstCommon.EMPTY_LINE) { // 若本行结尾是换行符或本行无内容，则直接绘制无须处理
            canvas?.drawText(line, paddingLeft.toFloat(), baseLineY, paint)
            return
        }
        var x = paddingLeft.toFloat()
        // 2.数出有多少个空格
        var sum = getSpaceCount(line)
        // tempLine: 用于存储接下来要开始绘制的文本主要是看最后一个是不是空格
        val tempLine =
            if (line[endIndex].code == ConstCommon.ASCII_SPACE) { // 最后一个字符是空格，则删掉空格
                sum--
                line.substring(0, line.length - 1)
            } else {
                line
            }
        // 3.根据空格数量计算每个空格的宽度
        val oneTextWidth = (measuredWidth - lineWidth - paddingLeft - paddingRight) / sum

        // 4.每找到一个单词，打印一次，如果后面有空格也打印出来
        var i = 0
        while (i < tempLine.length) {
            var wordStr = ""
            while ((tempLine[i].code != ConstCommon.ASCII_SPACE)
                && i < tempLine.length - 1
            ) {
                wordStr += tempLine[i]
                i++
            }
            wordStr += tempLine[i]
            var dw = StaticLayout.getDesiredWidth(wordStr, this.paint)
            if (tempLine[i].code == ConstCommon.ASCII_SPACE) {
                dw += oneTextWidth
            } // else tempLine[i]是本行最后一个字符的情况
            canvas?.drawText(wordStr, x, baseLineY, this.paint)
            x += dw
            i++
        }
    }


    /**
     * 从左往右念，中间没空格
     * 举例：中文
     */
    private fun drawChineseScaledText(
        canvas: Canvas?,
        line: String,
        baseLineY: Float,
        lineWidth: Float
    ) {
        if (line.isEmpty()) {
            return
        }
        var x = paddingLeft.toFloat()
        val endIndex = line.length - 1
        if (line[endIndex].code == ConstCommon.ASCII_ENTER || endIndex == ConstCommon.EMPTY_LINE) { // 若本行结尾是换行符或本行无内容，则直接绘制无须处理
            canvas?.drawText(line, x, baseLineY, paint)
            return
        }
        val oneTextWidth =
            (measuredWidth - lineWidth - paddingLeft - paddingRight) / endIndex
        for (element in line) {
            val textStr = element.toString()
            val dw = StaticLayout.getDesiredWidth(textStr, this.paint)
            canvas?.drawText(textStr, x, baseLineY, this.paint)
            x += dw + oneTextWidth
        }
    }


    /**
     * 从右往左念，中间有空格
     * 举例：阿拉伯语
     */
    private fun drawArabicScaledText(
        canvas: Canvas?,
        line: String,
        baseLineY: Float,
        lineWidth: Float
    ) {
        if (line.isEmpty()) {
            return
        }
        var x = measuredWidth - paddingRight.toFloat() //找到最右边的起点
        val endIndex = line.length - 1
        val sum = getSpaceCount(line)
        val oneTextWidth = (measuredWidth - lineWidth - paddingLeft - paddingRight) / sum
        var i = 0
        while (i < line.length) {
            var wordStr = ""
            while ((!charIsSymbol(line[i])
                        || (charIsFullStop(line[i]) && i + 1 < endIndex && i - 1 >= 0 && charIsNumber(
                    line[i + 1]
                ) && charIsNumber(line[i - 1])))
                && i < line.length - 1
            ) {
                wordStr += line[i]
                i++
            }
            var dw = StaticLayout.getDesiredWidth(wordStr, this.paint)
            x -= dw
            canvas?.drawText(wordStr, x, baseLineY, this.paint)
            if (charIsSymbol(line[i])) { // 下一次打单词之前加一个空格，不和wordStr加在一起的原因：碰到英文时他会默认空格加在左边，与阿拉伯语相反，会导致英语一边有两个空格，另一边没有空格
                dw = StaticLayout.getDesiredWidth(line[i].toString(), this.paint)
                x = if (line[i].code == ConstCommon.ASCII_SPACE &&
                    !(line[endIndex].code == ConstCommon.ASCII_ENTER || endIndex == ConstCommon.EMPTY_LINE)
                ) {
                    x - dw - oneTextWidth // 是空格且不是最后一行中的空格，需要拓宽
                } else {
                    x - dw
                }
            }
            canvas?.drawText(line[i].toString(), x, baseLineY, this.paint)
            i++
        }
    }

    /**
     * 语言组成：从左往右念，中间没空格
     * 优先级1（15）中有： 中文、日语、泰语、中文繁体
     * 未来要有新语种翻译时要加新的判断
     */
    private fun languageChineseType(): Boolean {
        return LanguageUtil.isChineseLanguage()
                || LanguageUtil.isJapaneseLanguage()
                || LanguageUtil.isThaiLanguage()
    }

    /**
     * 语言组成：从右往左念，中间有空格
     * 优先级1（15）中有：阿拉伯语、希伯来语
     */
    private fun languageArabicType(): Boolean {
        return LanguageUtil.isArabicLanguage() || LanguageUtil.isHebrewLanguage()
    }

    /**
     * 获取字符串中的空格数量
     */
    private fun getSpaceCount(input: String): Int {
        return input.count { it.code == ConstCommon.ASCII_SPACE }
    }

    /**
     * 判断当前字符是一个标点符号
     * 空格、双引号、单引号、逗号、句号
     */
    private fun charIsSymbol(word: Char): Boolean {
        return word.code == ConstCommon.ASCII_SPACE
                || word.code == ConstCommon.ASCII_DOUBLE_QUOTES
                || word.code == ConstCommon.ASCII_SINGLE_QUOTES
                || word.code == ConstCommon.ASCII_COMMA
                || word.code == ConstCommon.ASCII_FULL_STOP
    }

    /**
     * 判断当前字符是一个数字
     */
    private fun charIsNumber(word: Char): Boolean {
        return word.code >= ConstCommon.ASCII_NUM_ZERO
                && word.code <= ConstCommon.ASCII_NUM_NINE
    }

    private fun charIsFullStop(word: Char): Boolean {
        return word.code == ConstCommon.ASCII_FULL_STOP
    }
}